package usgs.bip.swap.process;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import usgs.bip.swap.view.StateListHelper;


public class MasterListDAO implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String fileName;
	private String fileContent;
	private ArrayList<String> speciesList;
	private TreeMap<String, TreeMap<String, ArrayList<Integer>>> taxa2stateMap;
	private TreeMap<String, TreeMap<String, ArrayList<Integer>>> state2taxaMap;
	private TreeMap<String, Integer> taxaCountList;
	private TreeMap<String, Integer> stateCountList;
	
	public MasterListDAO(String fileName){
		this.fileName = fileName;
		this.speciesList = new ArrayList<String>();
		this.taxa2stateMap = new TreeMap<String, TreeMap<String, ArrayList<Integer>>>();
		this.state2taxaMap = new TreeMap<String, TreeMap<String, ArrayList<Integer>>>();
		this.stateCountList = new TreeMap<String, Integer>();
		this.taxaCountList = new TreeMap<String, Integer>();
		this.fileContent = this.getFileContent();
	}
	
	public String getDefaultJSON(){
	
		StringBuffer json = new StringBuffer("");
		String jsonString = "";
	 
		
		try {
			json.append("{\n");

			Set<String> stateKey = this.stateCountList.keySet();
			int n = stateKey.size();
			int i = 0;
			json.append("\t\"state\" : {\n");
		    List<String> territories = StateListHelper.getTerritories();
			n -= territories.size();
			
			for(String state : stateKey){
				if(territories.contains(state)){
					continue;
				}
				json.append("\t\t" + "\"" + state + "\": " + this.stateCountList.get(state));
				if(i++ < n-1){
					json.append(",");
				}
				json.append("\n");

			}
			json.append("\t},\n");	 
			Set<String> taxaKey = this.taxaCountList.keySet();
			n = taxaKey.size();
			i = 0;
			json.append("\t\"taxa\" : {\n");
			for(String taxa : taxaKey){
				json.append("\t\t" + "\"" + taxa + "\": " + this.taxaCountList.get(taxa));
				if(i++ < n-1){
					json.append(",");
				}
				json.append("\n");

			}
			json.append("\t}\n");	  
			json.append("}\n");	  		
			}catch(Exception e){
				e.printStackTrace();
			}
			jsonString = json.toString();
			return jsonString;		
	}
	
	public String getState2TaxaJSON(){
		
		Set<String> taxa = this.taxaCountList.keySet();
		return this.getMap2JSON(this.state2taxaMap, taxa);
	}
	
	public String getTaxa2StateJSON(){
		Set<String> states =  this.stateCountList.keySet();
		return this.getMap2JSON(this.taxa2stateMap, states);
	}
	
	private String getMap2JSON(TreeMap<String, TreeMap<String, ArrayList<Integer>>> a2bMap, Set<String> bList){
		
		StringBuffer json = new StringBuffer("");
		String jsonString = "";
		int totalACount = a2bMap.size();
		int aCount = 1;
		
		try {
			json.append("{\n");
			for(Entry<String, TreeMap<String, ArrayList<Integer>>> entry : a2bMap.entrySet()) {
				  String a = entry.getKey();
				  TreeMap<String, ArrayList<Integer>> bMap = entry.getValue();
				  json.append("\t" + "\"" + a + "\": {\n");
				  int totalBCount = bMap.size();
				  int bCount = 1;
				  if(totalBCount > 0){
					  for(String bKey : bList){
						  if(!bMap.containsKey(bKey)){
							  json.append("\t\t" + "\"" + bKey + "\": {\n");
							  json.append("\t\t\t" + "\"count\": 0\n");
							  json.append("\t\t},\n");
						  }
					  }
				  }
				 
				  for(Entry<String, ArrayList<Integer>> subEntry : bMap.entrySet()) {
					  String b = subEntry.getKey();
					  json.append("\t\t" + "\"" + b + "\": {\n");
					  ArrayList<Integer> spArray = bMap.get(b);
					  int n = spArray.size();
					  json.append("\t\t\t" + "\"count\": " + n + ",\n");
					  json.append("\t\t\t" + "\"list\": [\n");
					  for(int i=0; i<n-1; i++){
						  json.append("\t\t\t\t" + "{\"value\" : [ " + this.speciesList.get(spArray.get(i)) + "]},\n");
					  }
					  json.append("\t\t\t\t" + "{\"value\" : [ " + this.speciesList.get(spArray.get(n-1)) + "]}\n");
					  json.append("\t\t\t]\n");
					  json.append("\t\t}");
					  if(bCount++ < totalBCount){
						  json.append(",");
					  }
					  json.append("\n");
				  }
				  json.append("\t}");
				  if(aCount++ < totalACount){
					  json.append(",");
				  }
				  json.append("\n");
			}
			json.append("}\n");
			
		}catch(Exception e){
			e.printStackTrace();
		}

		jsonString = json.toString();
		return jsonString;
		
	}

	/**
	 * @param fileContent the fileContent to set
	 */
	public void setFileContent(String fileContent) {
		this.fileContent = fileContent;
	}

	/**
	 * @return the fileContent
	 */
	private String getFileContent() {
		
		
		String output = "";
		URL url;
	 
		try {
			 
			url = new URL(this.fileName);
			HttpURLConnection huc = (HttpURLConnection) url.openConnection();
		    //HttpURLConnection.setFollowRedirects(false);
		    huc.setConnectTimeout(20 * 1000);
		    huc.connect();
		    //read the result from the server
		    BufferedReader rd  = new BufferedReader(new InputStreamReader(huc.getInputStream()));
	        StringBuilder sb = new StringBuilder();
			String line = rd.readLine();	// get rid of header : sciName\tcommonName\ttaxa\tStates
			int spIndex = 0;
			Integer tempInt = 0;
			
	        while ((line = rd.readLine()) != null)
	          {
	        		String[] cols = line.split("\t");
	         
	        		if(cols.length == 4){
	        			String sciName = cols[0];
	        			String commonName = cols[1];
	        			String value = '"' + sciName + "\",\"" + commonName + '"';
	        			this.speciesList.add(spIndex, value);
	        			String taxa = cols[2];
	        			taxa = taxa.trim();
	        			String states = cols[3];
	        			String[] stateList = states.split(";");
	        			int n = stateList.length;
	        			
	        			if(this.taxa2stateMap.get(taxa)== null){
	        				this.taxa2stateMap.put(taxa, new TreeMap<String, ArrayList<Integer>>());
	        				this.taxaCountList.put(taxa, 0);
	        			}
	        			tempInt = this.taxaCountList.get(taxa) + 1;
	        			this.taxaCountList.put(taxa, tempInt);
	        			
	        			for(int i=0; i<n; i++){
	        				String st = stateList[i];
	        				st = st.trim();
	        				// Process state2taxa matrix
	        				if(this.state2taxaMap.get(st) == null){
	        					this.state2taxaMap.put(st, new TreeMap<String, ArrayList<Integer>>());   
	        					this.stateCountList.put(st, 0);
	        				}
	        				tempInt = this.stateCountList.get(st) + 1;
	        				this.stateCountList.put(st,tempInt);
	        				
	        				TreeMap<String, ArrayList<Integer>> taxaMap =  this.state2taxaMap.get(st);
	        				if(taxaMap.get(taxa) == null){	
        						taxaMap.put(taxa, new ArrayList<Integer>());
	        				}
	        				ArrayList<Integer> spIndexList = taxaMap.get(taxa);
	        				spIndexList.add(spIndex);
	        				taxaMap.put(taxa, spIndexList);
        					this.state2taxaMap.put(st, taxaMap);

        					// Process taxa2state matrix
	        				TreeMap<String, ArrayList<Integer>> stateMap = this.taxa2stateMap.get(taxa);
	        				if(stateMap.get(st) == null){
	        					stateMap.put(st, new ArrayList<Integer>());
	        				}
	        				stateMap.get(st).add(spIndex);
	        				this.taxa2stateMap.put(taxa, stateMap);
	        			}
	        				        			
	        		}
	        		sb.append(line + '\n');
	        		spIndex++;
	          }

	        output = sb.toString();			
			
		}catch(Exception e){
			e.printStackTrace();
		}
		return output;
	}
}
